﻿using System;
using System.ComponentModel;
using System.ServiceModel;
using Airborne.ScrumPoker.Model.TeamFoundation;
using Airborne.ScrumPoker.Module.Communication;
using Airborne.ScrumPoker.Module.Events;
using Airborne.ScrumPoker.Module.Host.Model;
using Airborne.ScrumPoker.Module.Host.Services;
using Microsoft.Practices.Composite.Events;
using Microsoft.Practices.Composite.Wpf.Events;

namespace Airborne.ScrumPoker.Module.Host.Controllers
{
    public class HostController : IHostController, IDisposable
    {

        #region Constructor
        public HostController(IEventAggregator eventAggregator)
        {
            EventAggregator = eventAggregator;
        }
        #endregion

        #region Properties
        public ServiceHost ServiceHost
        {
            get;
            set;
        }
        public IEventAggregator EventAggregator { get; set; }
        #endregion

        #region IHostController Members

        public void Run()
        {
            BackgroundWorker worker = new BackgroundWorker();
            worker.DoWork += new DoWorkEventHandler(InitiateHost);
            worker.RunWorkerAsync();

            SubscribeToEvents();
        }

        private void InitiateHost(object sender, DoWorkEventArgs e)
        {
            ServiceHost = new ServiceHost(typeof(ScrumPokerClientConnection));
            ServiceHost.Open();
        }

        private void SubscribeToEvents()
        {
            ConnectionManager.Instance.ClientVote += ClientVote;
            ConnectionManager.Instance.ClientSubscribed += ClientSubscribed;
            ConnectionManager.Instance.ClientUnsubscribed += ClientUnsubscribed;

            EventAggregator.GetEvent<GenericEvent<int>>().Subscribe(StartTimer, ThreadOption.BackgroundThread, false, parms => parms.Topic == EventTopics.StartTimer && !ConnectionManager.Instance.TimerStarted);
            EventAggregator.GetEvent<GenericEvent<string>>().Subscribe(StopTimer, ThreadOption.BackgroundThread, false, parms => parms.Topic == EventTopics.StopTimer && ConnectionManager.Instance.TimerStarted);
            EventAggregator.GetEvent<GenericEvent<string>>().Subscribe(ResetVote, ThreadOption.BackgroundThread, false, parms => parms.Topic == EventTopics.ResetVote && !ConnectionManager.Instance.TimerStarted);
            EventAggregator.GetEvent<GenericEvent<ITeamWorkItem>>().Subscribe(WorkItemSelected, ThreadOption.BackgroundThread, false, parms => parms.Topic == EventTopics.WorkItemSelected && !ConnectionManager.Instance.TimerStarted);
        }

        private void ClientSubscribed(object sender, GenericEventArgs<string> e)
        {
            EventAggregator.GetEvent<GenericEvent<string>>().Publish(new EventParameters<string>(EventTopics.ClientSubscribed, e.Data));
        }

        private void ClientUnsubscribed(object sender, GenericEventArgs<string> e)
        {
            EventAggregator.GetEvent<GenericEvent<string>>().Publish(new EventParameters<string>(EventTopics.ClientUnsubscribed, e.Data));
        }

        private void ClientVote(object sender, ClientVotedEventArgs e)
        {
            Client client = new Client(e.Client, e.Vote);
            EventAggregator.GetEvent<ClientVotedEvent>().Publish(client);
        }


        private void StartTimer(EventParameters<int> parameters)
        {
            ConnectionManager.Instance.StartTimer(parameters.Value);
        }

        private void StopTimer(EventParameters<string> parameters)
        {
            ConnectionManager.Instance.StopTimer();
        }

        private void ResetVote(EventParameters<string> parameters)
        {
            ConnectionManager.Instance.ResetVote();
        }

        private void WorkItemSelected(EventParameters<ITeamWorkItem> parameters)
        {
            ConnectionManager.Instance.SelectWorkItem(parameters.Value);
        }
        #endregion

        #region IDisposable Members

        public void Dispose()
        {
            this.Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                ConnectionManager.Instance.ClientVote -= ClientVote;
                ConnectionManager.Instance.ClientSubscribed -= ClientSubscribed;
                ConnectionManager.Instance.ClientUnsubscribed -= ClientUnsubscribed;

                EventAggregator.GetEvent<GenericEvent<int>>().Unsubscribe(StartTimer);
                EventAggregator.GetEvent<GenericEvent<string>>().Unsubscribe(StopTimer);
                EventAggregator.GetEvent<GenericEvent<string>>().Unsubscribe(ResetVote);
                EventAggregator.GetEvent<GenericEvent<ITeamWorkItem>>().Unsubscribe(WorkItemSelected);

                if (ServiceHost.State == CommunicationState.Opened)
                {
                    ServiceHost.Close();
                }
            }
        }
        #endregion

    }
}
